'''
Created on 2009-10-9

@author: loudly
'''
from django import http
import django.template as template
from django.utils import simplejson
import django.core.urlresolvers as urlresolvers

import google.appengine.ext.db as db

from models import Game
from OfficialMahjongModels import OfficialMahjongGame
from OfficialMahjongModels import OfficialMahjongSession
from OfficialMahjongModels import OfficialMahjongHand

from standaloneView import StandaloneView
from OfficialMahjongUtils import seatRotate

WINDS = {0 : u'east', 1 : u'south', 2 : u'west', 3 : u'north'}
TABLE_SCORES = (4, 2, 1, 0)

class OfficialMahjongStandaloneView(object):
    '''
    classdocs
    '''


    def __init__(selfparams):
        '''
        Constructor
        '''

def _saveHand(game, session, newSession, hand, newHand):
    gameT = db.get(game.key())
    if gameT.roundsForNow > game.roundsForNow or (gameT.finished and not game.finished):
        raise db.Rollback
    game.put()
    
    if not newSession :
        sessionT = db.get(session.key())
        if sessionT.roundsForNow > session.roundsForNow or (sessionT.finished and not session.finished) :
            raise db.Rollback
    session.put()
    
    if newHand :
        hand.session = session
    
    if hand : 
        hand.put()
    
    return True

def _compareTableScore(x, y):
    
    ret = cmp(x[0], y[0])
    if ret != 0 :
        return ret
    else :
        return cmp(x[1], y[1])

def _updateSumScores(game, session, changedHand):
    
    ret = game.sessions.filter('roundNumber =', session.roundNumber).fetch(1)
    if len(ret) > 0:
        oldSession = ret[0]
        
        for i in range(0, 4) :
            game.sumScores[i] -= oldSession.sumScores[i]
    
    sumFans = []
    for i in range(0, 4) :
        sumFans.append([session.sumFans[i], 0 , i])
    
    sumFans.sort(_compareTableScore, reverse = True)
    
    needToCompareMaxFan = False
    
    for i in range(0, 3) :
        if sumFans[i][0] == sumFans[i + 1][0] :
            needToCompareMaxFan = True
            break
    
    if needToCompareMaxFan :
        hands = session.hands
        
        for i in range(0, 4) :
            currentPlayer = session.players[sumFans[i][2]]
            currentMaxFan = 0
            
            for hand in hands :
                if hand.roundNumber == changedHand.roundNumber : continue
                
                fan = hand.fans[hand.players.index(currentPlayer)]
                if fan > currentMaxFan :
                    currentMaxFan = fan
            
            fan = changedHand.fans[changedHand.players.index(currentPlayer)]
            if fan > currentMaxFan :
                currentMaxFan = fan
            
            sumFans[i][1] = currentMaxFan
    
    sumFans.sort(_compareTableScore, reverse = True)
    
    session.sumScores = [0, 0, 0, 0]
    for i in range(0, 4) :
        session.sumScores[sumFans[i][2]] = TABLE_SCORES[i]
        
        if i > 0 and _compareTableScore(sumFans[i], sumFans[i - 1]) == 0 :
            session.sumScores[sumFans[i][2]] = session.sumScores[sumFans[i - 1][2]]
        
        game.sumScores[sumFans[i][2]] += session.sumScores[sumFans[i][2]]
    
def playhand(request):
    
    ret = {}
    ret['success'] = True
    
    r = http.HttpResponse('', mimetype='application/json')
    
    gameKeyStr = request.POST['gameKeyStr']
    handNumber = int(request.POST['handNumber'])
    sessionNumber = int(request.POST['sessionNumber'])
    currentPlayers = request.POST['playerArr'].split(',')
    for i in range(0, 4) : currentPlayers[i] = unicode(currentPlayers[i], 'utf8')
    currentFans = request.POST['playerFanArr'].split(',')
    for i in range(0, 4) : currentFans[i] = int(currentFans[i])
    
    game = db.get(db.Key(gameKeyStr))
    
    lastSession = None
    lastHand = None
    
    if game.roundsForNow > 0 :
        lastSession = game.sessions.order('-roundNumber').fetch(1)[0]
    
    if lastSession != None and lastSession.roundsForNow > 0 :
        lastHand = lastSession.hands.order('-roundNumber').fetch(1)[0]
    
    #check if the sessionNumber is valid
    if sessionNumber >= game.totalSessions :
        ret['success'] = False
        ret['errorName'] = 'invalidSessionOrHand'
        ret['errorValue'] = 'session number %s exceed total sessions of this game %s' % (sessionNumber, game.totalSessions)
    
    if not ret['success'] :
        r.write(simplejson.dumps(ret))
        return r
    
    if sessionNumber > 0 and sessionNumber >= game.roundsForNow :
        if sessionNumber > game.roundsForNow or (sessionNumber == game.roundsForNow and not lastSession.finished ) :
            ret['success'] = False
            ret['errorName'] = 'invalidSessionOrHand'
            ret['errorValue'] = 'invalid session %s' % sessionNumber
    
    if not ret['success'] :
        r.write(simplejson.dumps(ret))
        return r
    
    currentSession = None
    currentHand = None
    
    if sessionNumber < game.roundsForNow :  #the session already exists:
        currentSession = game.sessions.filter('roundNumber =', sessionNumber).fetch(1)[0]
        
        if handNumber > currentSession.roundsForNow :
            ret['success'] = False
            ret['errorName'] = 'invalidSessionOrHand'
            ret['errorValue'] = 'invalid hand %s' % handNumber
            
        elif handNumber < currentSession.roundsForNow :
            currentHand = currentSession.hands.filter('roundNumber =', handNumber).fetch(1)[0]
            
    else : #new session
        if handNumber != 0 :
            ret['success'] = False
            ret['errorName'] = 'invalidSessionOrHand'
            ret['errorValue'] = 'new session, but handNumber != 0'
    
    if not ret['success'] :
        r.write(simplejson.dumps(ret))
        return r
    
    #check if players not match with origin players list
    for i in currentPlayers :
        if not i in game.players :
            ret['success'] = False
            ret['errorName'] = 'playersNotSame'
            ret['errorValue'] = 'current %s not in origin %s' % (i, str(game.players)) 
            
            break
    else :
        for i in game.players :
            if not i in currentPlayers :
                ret['success'] = False
                ret['errorName'] = 'playersNotSame'
                ret['errorValue'] = 'origin %s not in current %s' % (i, str(currentPlayers)) 
                
                break
    
    if not ret['success'] :
        r.write(simplejson.dumps(ret))
        return r
    
    newSession = False
    newHand = False
    
    if not currentSession :
        newSession = True
        game.roundsForNow = sessionNumber + 1
        
        fans = [0, 0, 0, 0]
        playerPosition = {}
        for i in range(0, 4) :
            playerPosition[game.players[i]] = i
        for i in range(0, 4) :
            fans[playerPosition[currentPlayers[i]]] =currentFans[i]
        
        currentSession = OfficialMahjongSession(game = game,
                                                players = game.players,
                                                roundNumber = sessionNumber,
                                                roundsForNow = 1,
                                                sumFans = fans,
                                                sumScores = [0, 0, 0, 0],
                                                parent = game)
    else :
        playerPosition = {}
        
        for i in range(0, 4) :
            playerPosition[currentSession.players[i]] = i
        
        for i in range(0, 4) :
            currentSession.sumFans[playerPosition[currentPlayers[i]]] += currentFans[i]
        
    if not currentHand :
        newHand = True
        currentHand = OfficialMahjongHand(roundNumber = handNumber,
                                          players = currentPlayers,
                                          fans = currentFans,
                                          roundWind = WINDS[(handNumber / 4) % 4],
                                          seatWind = WINDS[handNumber % 4],
                                          finished = True, 
                                          parent = game,
                                          )
        
        if not newSession :
            currentSession.roundsForNow = handNumber + 1
            if currentSession.roundsForNow == 16 : 
                currentSession.finished = True
                
                if game.roundsForNow == game.totalSessions :
                    game.finished = True
        
    else :
        for i in range(0, 4) :
            currentSession.sumFans[playerPosition[currentHand.players[i]]] -= currentHand.fans[i]
            
        currentHand.players = currentPlayers
        currentHand.fans = currentFans
        currentHand.roundWind = WINDS[(handNumber / 4) % 4]
        currentHand.seatWind = WINDS[handNumber % 4]
    
    if currentSession.finished :
        _updateSumScores(game, currentSession, currentHand)
    
    transaction_ret = db.run_in_transaction(_saveHand, game, currentSession, newSession, currentHand, newHand)
    if not transaction_ret :
        ret['success'] = False
        ret['errorName'] = 'rolledBack'
        ret['errorValue'] = ''
    else : 
        ret['success'] = True
        ret['playerArr'] = seatRotate(handNumber + 1, currentPlayers)
            
    r.write(simplejson.dumps(ret))
    
    return r

def startsession(request):
    
    gameKeyStr = request.POST['gameKeyStr']
    nextSessionNumber = int(request.POST['nextSessionNumber'])
    
    game = db.get(db.Key(gameKeyStr))
    
    lastSession = None
    
    if game.roundsForNow > 0 :
        lastSession = game.sessions.order('-roundNumber').fetch(1)[0]
    
    if nextSessionNumber < game.totalSessions and (not(lastSession and (not lastSession.finished))) :
        game.roundsForNow = nextSessionNumber + 1
        
        newSession = OfficialMahjongSession(game = game,
                                            players = game.players,
                                            roundNumber = nextSessionNumber,
                                            roundsForNow = 0,
                                            sumFans = [0, 0, 0, 0],
                                            sumScores = [0, 0, 0, 0],
                                            parent = game)
        
        transaction_ret = db.run_in_transaction(_saveHand, game, newSession, True, None, False)
    
    return http.HttpResponseRedirect(urlresolvers.reverse('views.play', 
                                                           kwargs={
                                                                'gameName': 'official_mahjong',
                                                                'gameKeyStr': gameKeyStr }
                                                           ))
